/**
 * Log4j the log output component for IE6
 * 
 * Copyright (c) 2010-2011 Benben, http://www.51jsr.com
 *
 * Usage: <script type="text/javascript" src="$url$/log4j.js"></script>
 * 		  <script>
 * 			//window.onbeforeunload = Log4j.closeConsole;
 * 			//Log4j.rootLogger = 4;
 *          Log4j.init(4);
 * 		  </script>
 * 
 * Version 101109E
 */
var Log4j = (function() {
	//Define variables
	var console, outHandler, idn = "   ", indentation = "",
		logger = {Info: 0, Warning: 1, Debug: 2, Error: 2, Step: 3},
		typeColor = {Step: "#aaa", Warning: "blue", Debug: "red", Error: "#f0f"},
		lsColor = ["red", "blue", "#f0f", "green"],
		lineSeparator = "----------------------------------------------------\n",
		
	//Initialize the console window
	initConsole = function() {
		var cslHtml = '';
		//Console page code
		cslHtml += '<html><head>';
		cslHtml += '<meta http-equiv="Content-Type" content="text/cslHtml; charset=utf-8"/>';
		cslHtml += '<title>Log4j Console => ' + document.title + '</title><style>';
		cslHtml += 'body{margin:0px}i{cursor:pointer}';
		cslHtml += 'table{width:100%;border-collapse:collapse;font:12px tahoma;table-layout:fixed}';
		cslHtml += 'th,td{text-align:left;padding-left:5px;border:solid #aaa}';
		cslHtml += 'th{height:26px;background-color:#ddd;border-width:0 1 1 0;font-weight:bold}';
		cslHtml += 'td{border-width:0 0 1;word-wrap:break-word;word-break:break-all;padding:3px}';
		cslHtml += '.even{background-color:#ffd}';
		cslHtml += '</style></head><body>';
		cslHtml += '<table><tr><th width=160px>Time</th><th width=70px>Type</th><th style="border-right:none">Message</th></tr></table>';
		cslHtml += '</body></html>';
		//The console window
		console = window.open('', '', 'width=640,height=160,left='
			+ (window.screen.width - 790)
			+ ',top='
			+ (window.screen.height - 230)
			+ ',scrollbars=yes,resizable=yes');
		console.document.write(cslHtml);
		//Output information in the DOM handle
		outHandler = console.document.body.firstChild;
		window.focus();
	};
	
	return {
		//Log of information on output
		rootLogger: 3,
		//Analysis level
		deepLevel: 5,
		//Initialization
		init: function(rlv, dlv) {
			window.onbeforeunload = this.closeConsole;
			this.rootLogger = rlv || 3;
			this.deepLevel = dlv || 5;
			this.$alt = window.alert;
			window.alert = function(msg, flag) {
				Log4j.debug("[ <u style='color:#80f'>Alert-Out</u> ] => " + msg);
				flag && Log4j.$alt("Log4j hang up!!");
			};
        },
		//Output ordinary hints
		info: function(msg) {
			this.out("Info", msg);
		},
		//Output warning messages or special
		warn: function(msg) {
			this.out("Warning", msg);
		},
		//Output debugging information
		debug: function(msg) {
			this.out("Debug", msg);
		},
		//Output of an information error
		error: function(msg) {
			this.out("Error", msg);
		},
		//Log output information
		out: function(type, msg) {
			//Judgement the present information output level
			if(logger[type] < this.rootLogger) {
				//Resets the console
				(!console || console.closed) && initConsole();
				//Output information row
				var row = outHandler.insertRow(1);
				row.insertCell(-1).innerHTML = (new Date).toLocaleString();
				row.insertCell(-1).innerHTML = type;
				row.insertCell(-1).innerHTML = "<pre>" + msg + "</pre>";
				typeColor[type] && (row.cells[0].style.color
					= row.cells[1].style.color
					= typeColor[type]);
				outHandler.rows.length % 2 && (row.className = "even");
			}//Endif
		},
		//Close the console window
		closeConsole: function() {
			console && !console.closed && console.close();
		},
		//Analysis variable arguments
		analysis: function(para, flag) {
			var tmp, paraStr = [];
			if(typeof para == "string") {
				//String
				return "\"" + para.replace(/</g, "&lt;").replace(/</g, "&gt;") + "\"";
			}else if(!para || para.constructor == RegExp) {
				//undefine, null, false, 0, RegExp
				return para;
			}else if(para.constructor == Date) {
                //Date
                return "Date(" + para.toLocaleString() + ")";
			}else if(para.constructor == Array) {
				//Array
				indentation += idn;
				for(var i = -1, len = para.length; ++i < len;)
					paraStr.push(this.analysis(para[i]));
				paraStr = "[\n" + indentation + paraStr.join(", ");
				return paraStr + "\n" + (indentation = indentation.slice(idn.length)) + "]";
			}else if(typeof para == "function") {
				//Function
				tmp = (tmp = para.toString().match(/^function [^(]+/)) ? tmp : "function";
				return tmp + "(){<i title='" + para + "'>...</i>}";
			}else if(typeof para == "object") {
				//Object 
				tmp = /[189]/.test(para.nodeType) ? "function DomElement" : 
				    "ctrlKey" in para ? "function Event" : 
				        "zIndex" in para ? "function CssStyle" :
			                 para.constructor ? para : "function Unknown";
				if(tmp == para)
				    while(/^function ?\(/.test(tmp = tmp.constructor));
				tmp = "@" + tmp.toString().match(/function (\w+)/)[1];
				//deepLevel
				if(this.deepLevel == flag)
				    return "#" + flag + tmp;
				flag = flag || 0;
				if(tmp == "@HashMap") {
					//HashMap
					var keys = para.keys(), lsc;
					//Cycle queue
					lsColor.push(lsc = lsColor.shift());
					for(var i = -1, len = keys.length; ++i < len;) {
						paraStr.push("@HashMap<u style='color:" + lsc + "'>.get(\"" + keys[i] + "\")</u> => ");
						paraStr.push(this.analysis(para.get(keys[i]), flag + 1));
						i + 1 != len && paraStr
						  .push("<a style='color:" + lsc + "'>\n" + lineSeparator.slice(idn.length * flag) + "</a>");
					}//Endfor
					paraStr = paraStr.join('').replace(/\n/g, "\n" + (flag ? indentation + idn : ""));
					return paraStr;
				}else {
					//Object
					tmp == "@Event" && (flag = this.deepLevel - 2);
                    tmp == "@DomElement" && (flag = this.deepLevel - 1);
					indentation += idn;
					tmp = tmp != "@Object" ? tmp + " " : "";
					for(var i in para)
						!(i in {}) && paraStr.push(i + ": " + this.analysis(para[i], flag + 1));
					tmp = (tmp + "{#N" + paraStr.join(", #N")).replace(/#N/g, "\n" + indentation);
					tmp += "\n" + (indentation = indentation.slice(idn.length)) + "}";
					return tmp;
				}//Endif
			}//Endif
			return para;
		},
		//Function debugger
		debuger: function() {
            var args = Array.apply(null, arguments),
                scope = args.pop(), cfg = args.pop(), fnBody = scope.toString(),
                fnLine = fnBody.replace(/functio[^\(]*/, cfg.id + "_DEBUG = function")
                    .replace(/((\s*(?:\/\*.*?\*\/\r)|(?:\/\/([^#][^\n]+))))\n/g, "\n")
                    .replace(/([=\(])\s*{\s*/g, "$1{")
                    .replace(/((\s*)(?:if|for)[^{]+?)\r\n([^\r\n]+)/g, "$1 {\n$3$2}")
                    .split("\n"),
				//Step execute function
                stepRun = function(curLine, evalFn) {
                    //infoHead
                    var info = "Debug ID: "
                        + cfg.id + "\n"
                        + curLine + "\n\n"
                        + "======================================[Context]==\n",
                        param = cfg.context ? cfg.context.split("|") : [], i = 0;
					//Concern for the context of the value of the variable
                    for(; i < param.length; i++)
                        info += param[i] + "\t= " + evalFn(param[i]) + "\n";
                    info += "======================================[Context]==\n";
					//Whether step && Continue to perform
                    if(cfg.step && !confirm(info + "\nWhether to continue?"))
                        throw new Error("Step stop");
                    Log4j.out("Step", "<pre>" + info + "</pre>");
                },
                debugerCode = ["try{"], ii = 0, parseFlag, tmp;
			//Rewriting the function of the body
            for(; ii < fnLine.length - 1; ii++) {
				//Filter one-line comments | Deal with the breakpoint (Begin & End)
                if((tmp = fnLine[ii].match(/^\s*(?:\/\/(.*))/))) {
					//If a breakpoint
                    /#debug/.test(tmp[1]) && debugerCode.push("cfg.step = true;");
                    /#stop/.test(tmp[1]) && debugerCode.push("cfg.step = false;");
                    continue;
                }//Endif
                if(!/\S/.test(fnLine[ii])) continue;
                if(parseFlag || /^\s*}/.test(fnLine[ii]))
                    debugerCode.push(fnLine[ii]);
                else
                    debugerCode.push("stepRun('Current line [ "
                        + (ii + 1) + " ] => "
                        + fnLine[ii].replace(/[\r\n]/g, "").replace(/'/g,"\\'")
                        + "', function(t){try{return eval(t)}catch(e){}});"
                        + fnLine[ii]);
                parseFlag = /.*,\s*$/.test(fnLine[ii]);
            }//Endfor
            debugerCode.push("}\n" + cfg.id + "_DEBUG.apply(cfg.scope || scope, args);}catch(LogE){Log4j.error(LogE.message)}");
            return eval(debugerCode.join("\n"));
        }
	}//Endreturn
})();
//Expanded function prototypes
Function.prototype.debug = function() {
    return Log4j.debuger.apply(
        this,
        Array.apply(null, arguments).concat([this])
    );
}